#include "MatrixStack.h"

#include <assert.h>

MatrixStack *MatrixStack::g_instance = NULL;

void MatrixStack::Create()
{
	if(g_instance == NULL)
	{
		g_instance = new MatrixStack();
	}
}

MatrixStack *MatrixStack::ReturnInstance()
{
	assert(g_instance != NULL);
	return g_instance;
}

void MatrixStack::Delete()
{
	delete g_instance;
	g_instance = NULL;
}

MatrixStack::MatrixStack()
{
	//Push the identity matrix on the bottom and initalise
	D3DXMATRIX tempMatrix;
	D3DXMatrixIdentity(&tempMatrix);
	D3DXMatrixIdentity(&m_viewMatrix);
	D3DXMatrixIdentity(&m_projectionMatrix);
	D3DXMatrixIdentity(&m_worldMatrix);

	//Identity
	m_matrixStack.push(tempMatrix);
	//World
	m_matrixStack.push(tempMatrix);
	//View
	m_matrixStack.push(tempMatrix);
	//Projection
	m_matrixStack.push(tempMatrix);
}

void MatrixStack::Pop()
{
	if(!m_matrixStack.empty())
	{
		m_matrixStack.pop();
	}
}

void MatrixStack::Push(const D3DXMATRIX &matrix)
{
	D3DXMATRIX top = m_matrixStack.top();

	top = (top * matrix);
	m_matrixStack.push(top);
}

void MatrixStack::SetViewMatrix(const D3DXMATRIX &viewMatrix)
{
	m_viewMatrix = viewMatrix;
}

void MatrixStack::SetProjectionMatrix(const D3DXMATRIX &projectionMatrix)
{
	m_projectionMatrix = projectionMatrix;
}

void MatrixStack::SetWorldMatrix(const D3DXMATRIX &worldMatrix)
{
	m_worldMatrix = worldMatrix;

	//Clear the projection, view and world matrices
	Pop();
	Pop();
	Pop();

	//Push the world, then view, then projection matrices
	Push(m_worldMatrix);
	Push(m_viewMatrix);
	Push(m_projectionMatrix);
}